﻿using Avalonia;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using OfficeOpenXml;

namespace ExcelMerge;

public class Entry
{
    public static MainWindowArgs MainWindowArgs { get; private set; }
    // Initialization code. Don't use any Avalonia, third-party APIs or any
    // SynchronizationContext-reliant code before AppMain is called: things aren't initialized
    // yet and stuff might break.
    [STAThread]
    public static void Main(string[] args)
    {
        Console.OutputEncoding = Encoding.UTF8;
        if (args.Length == 1 && args[0].Equals("test", StringComparison.OrdinalIgnoreCase))
        {
            diff_match_patchTest.Test();
            return;
        }

        ExcelPackage.LicenseContext = LicenseContext.NonCommercial;
        
        if (args.Length == 2)
        {
            StartDiff(args);
        }
        else if (args.Length == 4)
        {
            StartMerge(args);
        }
        else
        {
            throw new Exception("参数数量不对");
        }
    }

    // Avalonia configuration, don't remove; also used by visual designer.
    private static AppBuilder BuildAvaloniaApp() =>
            AppBuilder.Configure<App>()
            .UsePlatformDetect()
            .WithInterFont()
            .LogToTrace();

    private static void StartDiff(string[] args)
    {
        List<CellDiffItem> originItems = null;
        List<CellDiffItem> newItems = null;
        
        Task.WaitAll(Task.Run(() => originItems = GetDiffItems(args[0])),
            Task.Run(() => newItems = GetDiffItems(args[1])));
        
        var diffs = new diff_match_patch<CellDiffItem>().diff_main(originItems, newItems);
        MainWindowArgs = new MainWindowArgs(WindowMode.Diff, new DiffViewArgs(originItems,newItems,diffs));
        BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);
    }
    
    private static void StartMerge(string[] args)
    {
        List<CellDiffItem> originItems = null;
        List<CellDiffItem> selfItems = null;
        List<CellDiffItem> otherItems = null;

        var start = DateTime.Now;
        Task.WaitAll(
            Task.Run(() => originItems = GetDiffItems(args[0])),
                        Task.Run(() => selfItems = GetDiffItems(args[1])), 
                        Task.Run(() => otherItems = GetDiffItems(args[2])));
        
        List<Patch<CellDiffItem>> selfPatches = null;
        List<Patch<CellDiffItem>> otherPatches = null;
        
        Task.WaitAll(
            Task.Run(() => selfPatches = GetPatches(originItems, selfItems)),
                        Task.Run(() => otherPatches = GetPatches(originItems, otherItems)));
        var merge = diff_match_patch<CellDiffItem>.patch_try_merge(selfPatches, otherPatches);
        if (merge.selfRemainPatches.Count != 0 || merge.otherRemainPatches.Count != 0)
        {
            MainWindowArgs = new MainWindowArgs(WindowMode.Merge, new MergeModel(
                originItems,
                selfPatches,
                otherPatches,
                merge.selfRemainPatches, 
                merge.otherRemainPatches,
                merge.mergedPatches,
                (items, patches) =>
                {
                    ApplyMerge(items,patches,args[3]);
                }));
            BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);
            return;
        }

        ApplyMerge(originItems,merge.mergedPatches,args[3]);
        var end = DateTime.Now;
        Console.WriteLine($"合并成功，耗时 {(end-start).TotalMilliseconds} ms");
    }
    
    private static List<CellDiffItem> GetDiffItems(string path)
    {
        if (!File.Exists(path))
        {
            throw new Exception("目标文件不存在:" + path);
        }
        var package = new ExcelPackage(path);
        if (package.Workbook.Worksheets.Count == 0)
        {
            package.Dispose();
            throw new Exception("目标文件没有sheet:" + path);
        }

        var sheet = package.Workbook.Worksheets[0];

        var rowCount = 0;
        var colCount = 0;
        var dataRowCount = 0;
        var dataColCount = 0;

        foreach (var cell in sheet.Cells)
        {
            rowCount = Math.Max(rowCount, cell.Start.Row);
            colCount = Math.Max(colCount, cell.Start.Column);

            if (cell.Value != null && !string.IsNullOrWhiteSpace(cell.Value.ToString()))
            {
                dataRowCount = Math.Max(dataRowCount, cell.Start.Row);
                dataColCount = Math.Max(dataColCount, cell.Start.Column);
            }
        }

        var items = new List<CellDiffItem>();
        for (int i = 1; i <= dataRowCount; i++)
        {
            for (int j = 1; j <= dataColCount; j++)
            {
                items.Add(new (i,j,sheet.Cells[i, j]));
            }
            items.Add(new(i,dataColCount+1));
        }
        //package.Dispose();
        return items;
    }

    private static List<Patch<CellDiffItem>> GetPatches(List<CellDiffItem> originItems,List<CellDiffItem> newItems)
    {
        var dmp = new diff_match_patch<CellDiffItem>();
        return dmp.patch_make(originItems, newItems);
    }

    private static void ApplyMerge(List<CellDiffItem> originItems,List<Patch<CellDiffItem>> patches,string outputPath)
    {
        var newItems = diff_match_patch<CellDiffItem>.patch_apply(patches, originItems,out _);
        // 创建一个新的Excel包（即新的Excel文件）
        using (var package = new ExcelPackage())
        {
            // 添加一个工作表
            var worksheet = package.Workbook.Worksheets.Add("Sheet1");
            int rowIndex = 1;
            int colIndex = 1;
            foreach (var item in newItems)
            {
                if (item.IsLineFeed())
                {
                    rowIndex++;
                    colIndex = 1;
                    continue;
                }
                item.ToCell(worksheet.Cells[rowIndex,colIndex]);
                colIndex++;
            }
            
            // 将文件保存到磁盘
            FileInfo fi = new FileInfo(outputPath);
            package.SaveAs(fi);
        }
    }
}